Technical Q&A QA1262
Calculating the video frame rate of an MPEG-1 or MPEG-2 movie


Q: How do I calculate the video frame rate of an MPEG-1 or MPEG-2 movie?

A: The easiest way to get this information is with the new MediaGetPublicInfo function, which was introduced in QuickTime 5 (see MediaHandlers.h). Simply pass the selector kMHInfoEncodedFrameRate .

Note also for MPEG media there is a bug (r. 3236091) in QuickTime 6 which requires you to first task the movie using the MoviesTask function before calling MediaGetPublicInfo to get the frame rate information.

For other media types (including the new MPEG-4 format) you must continue to compute the frame rate using the "old" method where the frames are counted using GetMediaSampleCount (or GetMovieNextInterestingTime ), and the media duration and time scale are used along with this value to derive the frame rate. Listing 1 below shows how this is done:



Listing 1. Listing 1 - Calculating the video frame rate of an MPEG movie.

#include <QuickTime/QuickTime.h>

#define     kCharacteristicHasVideoFrameRate    FOUR_CHAR_CODE('vfrr')
#define     kCharacteristicIsAnMpegTrack        FOUR_CHAR_CODE('mpeg')

#define BailOnMoviesErr(err) {if (err) goto bail; }


OSErr GetMovieFPS(Movie theMovie, short *fps)
{
    MediaHandler mpegMediaHandler = nil;
    Track        theTrack = nil;
    Media        myMedia = nil;
    OSErr        err = noErr;
    Boolean      isMpeg = false;

        /* initialize frame rate value */
    *fps = 0;
    
    if (theMovie == nil) goto bail;
    
        /* get the video track */
    theTrack = GetMovieIndTrackType(theMovie,
                                    1,
                                    kCharacteristicHasVideoFrameRate,
                                    movieTrackCharacteristic);
    err = GetMoviesError();
    BailOnMoviesErr(err != noErr);
    
        /* get the track media */
    myMedia = GetTrackMedia(theTrack);
    err = GetMoviesError();
    BailOnMoviesErr(err != noErr);
    
        /* get a reference to the media handler component */
    mpegMediaHandler = GetMediaHandler(myMedia);
    err = GetMoviesError();
    BailOnMoviesErr(err != noErr);
    
        /* is this the mpeg media handler? */
    err = MediaHasCharacteristic(mpegMediaHandler,
                                 kCharacteristicIsAnMpegTrack,
                                 &isMpeg);
    if ((err == noErr) && isMpeg)
    {
        MHInfoEncodedFrameRateRecord encodedFrameRate;
        Size encodedFrameRateSize = sizeof(encodedFrameRate);
            
            /* due to a bug in QuickTime, we must task the movie
                first before obtaining our frame rate value */
        MoviesTask( theMovie, 0 );
        
            /* get the static frame rate */
        err = MediaGetPublicInfo(mpegMediaHandler,
                                 kMHInfoEncodedFrameRate,
                                 &encodedFrameRate,
                                 &encodedFrameRateSize);
        if (err == noErr)
        {                
            Fixed staticFrameRate = 0;

            staticFrameRate = encodedFrameRate.encodedFrameRate;
                /* we'll round this value for simplicity - you could
                    parse the value to also obtain the fractional
                    portion as well. */
            *fps = FixRound(staticFrameRate);
        }
    }
    else /* were dealing with non-MPEG media, so use the "old" method */
    {
        long sampleCount = 0;
        
            /* get the number of samples in the media */
        sampleCount = GetMediaSampleCount(myMedia);
        err = GetMoviesError();
        BailOnMoviesErr(err != noErr);
        
        if (sampleCount)
        {
            TimeValue duration;
            TimeValue timeScale;
            Fixed staticFrameRate = 0;
            double frameRate;
            
                /* find the media duration */
            duration = GetMediaDuration(myMedia);
            err = GetMoviesError();
            BailOnMoviesErr(err != noErr);
            
                /* get the media time scale */
            timeScale = GetMediaTimeScale(myMedia);
            err = GetMoviesError();
            BailOnMoviesErr(err != noErr);
            
                /* calculate the frame rate:
            frame rate = (sample count * media time scale) / media duration 
                 */
            frameRate = sampleCount*(double)timeScale/(double)duration;
            staticFrameRate = X2Fix(frameRate);
                /* we'll round this value for simplicity - you could
                    parse the value to also obtain the fractional
                    portion as well. */
            *fps = FixRound(staticFrameRate);
        }
    }

bail:

    return err;
}



Alternately, you could count the MPEG video frames using GetMovieNextInterestingTime as described in QTMTB 54 , then use the media duration and time scale values to compute the frame rate. The code snippet in Listing 2 below demonstrates this technique:



Listing 2. Listing 2 - Calculating the frame rate using GetMovieNextInterestingTime.

#include <QuickTime/QuickTime.h>
long GetFrameCount (Movie theMovie)
{   
    long        frameCount = 0;
    TimeValue   curMovieTime;
    
    if (theMovie == NULL)
        goto bail;
    
        // due to a bug in QuickTime 6 we
        // must task the movie first
    MoviesTask( theMovie, 0 );
    
    curMovieTime = 0;
    while( curMovieTime >= 0 ) 
    {
        GetMovieNextInterestingTime( 
                                    theMovie, 
                                    nextTimeStep,
                                    0, NULL,
                                    curMovieTime,
                                    fixed1,
                                    &curMovieTime,
                                    NULL );
        frameCount++;
    }
    
    frameCount--; // there's an extra time step at the end of the movie
    
bail:
    
    return(frameCount);
}

OSErr GetMovieFPS(Movie theMovie, TimeValue *fps)
{
    OSErr err = noErr;
    TimeValue duration=0, 
              timeScale=0,
              movieDurationInSeconds;
                    
        /* initialize fps value */
    *fps = 0;
    
        /* get movie duration */
    duration = GetMovieDuration(theMovie);
    err = GetMoviesError();
    BailOnMoviesErr(err != noErr);
    
        /* get movie time scale */
    timeScale = GetMovieTimeScale(theMovie);
    err = GetMoviesError();
    BailOnMoviesErr(err != noErr);

        /* get movie length in seconds */
    movieDurationInSeconds = duration / timeScale;
        /* calculate frame rate */
    *fps = GetFrameCount (theMovie) / movieDurationInSeconds;

bail:

    return(err) ;
}




[Jun 02, 2003]


Developer Documentation | Technical Notes | Development Kits | Sample Code